package domain;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;

import domain.exceptions.ComplaintMyItemException;
import domain.exceptions.RequiredFieldsException;

@Entity
@Table(name = "articulos")
public class Item extends PersistentEntity {
	public enum Type{auction, normal};
	
	private String name;
	private double precio;
	private String description;
	private Date publicationDate;
	private int count;
	private boolean newItem;
	private int visitCounter;
	private boolean priority;
	private boolean suspended;
	private boolean active;
	@Enumerated(EnumType.STRING)
	private Type type;
	
	//TODO: Crear la imagen como una entity propia (tabla, referenciando al articulo)
	@Embedded
	private Image image;
	
	@ManyToOne
	@JoinColumn(name = "usuario")
	private User user;
	
	@ManyToOne
	@JoinColumn(name = "categoria")
	private Category category;

	@OneToMany(mappedBy="item")
	@Cascade(value = {CascadeType.ALL, CascadeType.DELETE_ORPHAN})
	@JoinColumn(name="item_id")
	@Sort(type=SortType.NATURAL)
	private SortedSet<Question> questions;	

	@OneToMany
	@Cascade(value=CascadeType.ALL)
	@JoinColumn(name="articulo")
	private List<Complaint> complaints;
	
	//Hibernate
	public Item() {
	}
	
	public Item(String name, double precio, String description, Date publicationDate, 
			int count, boolean newItem, User user, Category category, boolean priority, Type type){
		if(name.isEmpty() || name==null || description==null 
				|| publicationDate == null || user==null || category==null){
			throw new RequiredFieldsException();
		}
		if( count<0 || precio<0 || description.isEmpty())
			throw new IllegalArgumentException();
		this.name = name;
		this.precio = precio;
		this.description = description;
		this.publicationDate = publicationDate;
		this.count = count;
		this.newItem = newItem;
		this.user = user;
		this.category = category;
		this.priority = priority;
		this.type=type;
	}
	
//	public void modifyItem(String name, double precio, String description, Date publicationDate, 
//			int count, boolean newItem, User user, Category category, boolean priority, Type type){
//		if(name.isEmpty() || name==null || description==null 
//				|| publicationDate == null || user==null || category==null){
//			throw new RequiredFieldsException();
//		}
//		if( count<0 || precio<0 || description.isEmpty())
//			throw new IllegalArgumentException();
//		this.name = name;
//		this.precio = precio;
//		this.description = description;
//		this.publicationDate = publicationDate;
//		this.count = count;
//		this.newItem = newItem;
//		this.user = user;
//		this.category = category;
//		this.priority = priority;
//		this.type=type;
//	}
	
	public SortedSet<Question> getQuestions() {
		return questions;
	}

	public void setQuestions(SortedSet<Question> questions) {
		this.questions = questions;
	}
	
	public void addQuestion(Question q){
		if(questions==null){
			questions = new TreeSet<Question>();
		}
		questions.add(q);
	}
	
	public void removeQuestion(Question q){
		questions.remove(q);
	}
	
	public void addComplaint(Complaint complaint) throws ComplaintMyItemException{
		
		if(complaint.getUser() == this.getUser())
			throw new ComplaintMyItemException("You cant complaint your item");
		if(complaints==null){
			complaints = new ArrayList<Complaint>();
		}
		complaints.add(complaint);
	}
	
	public boolean canComplain(User user){
		if(user.equals(this.user))
			return false;
		for(Complaint c: complaints){
			if(c.getUser().equals(user)){
				return false;
			}
		}
		return true;
	}
	
	public void addStock(int units) {
		if (units > 0) {
			this.count += units;
		}
	}
	
	public Image getImage(){
		return image;
	}
	
	public void setImage(Image image){
		this.image=image;
	}	

	public void setVisitCounter(int countVisit){
		if(countVisit<0){
			throw new IllegalArgumentException();
		}
		this.visitCounter = countVisit;
	}
	
	public void decrementStock(int count){
		if(this.count==0 || (this.count - count) < 0){
			throw new IllegalArgumentException();
		}
		this.count -= count;
	}
	
	public String getName() {
		return name;
	}

	public double getPrecio() {
		return precio;
	}

	public String getDescription() {
		return description;
	}

	public Date getPublicationDate() {
		return publicationDate;
	}

	public int getCount() {
		return count;
	}

	public boolean getNewItem() {
		return newItem;
	}

	public int getVisitCounter() {
		return visitCounter;
	}
	
	public void incrementVisitCounter() {
		this.visitCounter++;
	}

	public User getUser() {
		return user;
	}

	public Category getCategory() {
		return category;
	}
	
	public boolean getPriority() {
		return priority;
	}

	public void setPriority(boolean priority) {
		this.priority = priority;
	}
	
	public Type getType(){
		if(this.type==null)
			return Type.normal;
		return this.type;
	}

	public String toString() {
		return super.getId() + this.name + "\n" + this.description + "\n" + this.precio;
	}

	public void setName(String name) {
		if(name.isEmpty() || name==null){
			throw new RequiredFieldsException();
		}
		this.name = name;
	}

	public void setPrecio(double precio) {
		if(precio<0)
			throw new IllegalArgumentException();
		this.precio = precio;
	}

	public void setDescription(String description) {
		if(description==null){
			throw new RequiredFieldsException();
		}
		if(description.isEmpty())
			throw new IllegalArgumentException();
		this.description = description;
	}

	public void setCount(int count) {
		if( count<0 )
			throw new IllegalArgumentException();
		this.count = count;
	}

	public void setNewItem(boolean newItem) {
		this.newItem = newItem;
	}

	public void setCategory(Category category) {
		if(category==null){
			throw new RequiredFieldsException();
		}
		this.category = category;
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}

	public List<Complaint> getComplaints() {
		return complaints;
	}

	public boolean canBuy(User user) {
		return !user.getIsBlock() && !user.equals(this.user) && !this.user.getIsBlock();
	}

	public boolean canAsk(User user) {
		return !user.getIsBlock() && !user.equals(this.user) && !this.user.getIsBlock();
	}

	public boolean canAnswer(User user) {
		return !user.getIsBlock() && user.equals(this.user);
	}

	public boolean isOwner(User user) {
		return user.equals(this.user);
	}

	public void setSuspended(boolean suspended) {
		this.suspended = suspended;
	}

	public boolean getSuspended() {
		return suspended;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result
				+ ((publicationDate == null) ? 0 : publicationDate.hashCode());
		result = prime * result + ((user == null) ? 0 : user.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Item other = (Item) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (publicationDate == null) {
			if (other.publicationDate != null)
				return false;
		} else if (!publicationDate.equals(other.publicationDate))
			return false;
		if (user == null) {
			if (other.user != null)
				return false;
		} else if (!user.equals(other.user))
			return false;
		return true;
	}
}
